package com.suray.wcs.web.system.controller;

import com.suray.basic.wcs.path.core.Node;
import com.suray.basic.wcs.path.enums.NodeStatus;
import com.suray.basic.wcs.path.enums.NodeType;
import com.suray.basic.wcs.utils.Coord;
import com.suray.basic.wcs.utils.LoggerUtil;
import com.suray.basic.wcs.utils.ModuleType;
import com.suray.basic.wcs.utils.WcsFuncUtil;
import com.suray.commin.annotation.Log;
import com.suray.commin.core.controller.BaseController;
import com.suray.commin.core.controller.ResponseData;
import com.suray.commin.core.page.TableDataInfo;
import com.suray.commin.core.utils.FileUtils;
import com.suray.commin.core.utils.SpringContextHolder;
import com.suray.commin.core.utils.StringUtils;
import com.suray.commin.enmus.BusinessType;
import com.suray.rgv.RgvInterface;
import com.suray.rgv.instance.RgvInstance;
import com.suray.system.run.random.code.LadderNavigate;
import com.suray.type.RgvMapTagDirection;
import com.suray.wcs.res.enums.RgvType;
import com.suray.wcs.service.core.util.CommonUtil;
import com.suray.wcs.service.core.util.ExcelMapUtil;
import com.suray.wcs.service.core.util.LockNodeManager;
import com.suray.wcs.service.core.util.ReadExcel;
import com.suray.wcs.service.enums.DetailProcess;
import com.suray.wcs.service.enums.TaskType;
import com.suray.wcs.service.init.SystemInit;
import com.suray.wcs.service.pojo.*;
import com.suray.wcs.service.resmap.WriteMap;
import com.suray.wcs.service.system.bo.ResourcesLockNodeBO;
import com.suray.wcs.service.system.bo.ResourcesNodeBO;
import com.suray.wcs.service.system.entity.*;
import com.suray.wcs.service.system.service.impl.*;
import com.suray.wcs.service.websocket.NodeInfoPush;
import com.suray.wcs.web.system.controller.thread.WriteMapUtil;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.collections4.map.HashedMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.*;

/**
 * <p>
 * 库区节点前端控制器
 * </p>
 *
 * @author cooper
 * @since 2019-06-26
 */
@RestController
@RequestMapping("/node")
@CrossOrigin
public class NodeDBController extends BaseController {
    @Autowired
    private NodeDBServiceImpl nodeDBService;
    @Autowired
    private RgvDBServiceImpl rgvDBService;
    private Logger log = LoggerFactory.getLogger(this.getClass());
    @Autowired
    private TaskDBServiceImpl taskDBService;
    @Autowired
    private ReadExcel readExcel;
    @Autowired
    private TaskDetailServiceImpl taskDetailService;
    @Autowired
    private WareHouseDBServiceImpl wareHouseDBService;

    /**
     * 查询节点列表
     *
     * @return
     */
    @ApiOperation("查询节点信息")
    @PreAuthorize("@ss.hasPermi('nodedb:list')")
    @GetMapping(value = "/list")
    public TableDataInfo list(NodeDB nodeDB) {
        startPage();
        List<NodeDB> list = nodeDBService.selectNodeList(nodeDB);
        try {
            for (NodeDB db : list) {
                StringBuffer forbidRgvsStr = new StringBuffer();
                if (StringUtils.isNotEmpty(db.getForbidRgvs())) {
                    for (String param : db.getForbidRgvs().split("-")) {
                        RgvType rgvType = RgvType.parseState(Integer.parseInt(param));
                        if (rgvType == null) {
                            forbidRgvsStr.append(param + ":未知车辆类型->");
                        } else {
                            forbidRgvsStr.append(rgvType.toString() + "-");
                        }
                    }
                }
                if (StringUtils.isNotEmpty(forbidRgvsStr)) {
                    db.setForbidRgvsStr(forbidRgvsStr.delete(forbidRgvsStr.lastIndexOf("-"), forbidRgvsStr.length()).toString());
                }
            }
        } catch (Exception e) {
            WcsFuncUtil.exceptionLog(e, this.getClass());
        }
        return getDataTable(list);
    }

    /**
     * 获取节点
     */
    @ApiOperation("获取方案")
    @GetMapping(value = "/{programmeId}")
    public ResponseData getInfo(@PathVariable Long programmeId) {
        NodeDB nodeDB = nodeDBService.getBaseMapper().selectById(programmeId);
        if (StringUtils.isNotEmpty(nodeDB.getForbidRgvs())) {
            nodeDB.setNodeRgvType((Long[]) ConvertUtils.convert(nodeDB.getForbidRgvs().split("-"), Long.class));
        }
        return ResponseData.success(nodeDB);
    }

    @PreAuthorize("@ss.hasPermi('nodedb:export')")
    @GetMapping("/export")
    @ApiOperation("导出地图")
    public ResponseData export() {
        //默认所有
        List<NodeDB> list = nodeDBService.selectNodeList(new NodeDB());
        ExcelMapUtil<NodeDB> util = new ExcelMapUtil<NodeDB>(NodeDB.class);
        return util.exportMapExcel(list, "地图数据");
    }

    /**
     * 一键打码
     *
     * @return
     */
    @Log(title = "库区节点前端控制", method = "一键打码", businessType = BusinessType.UPDATE)
    @PreAuthorize("@ss.hasPermi('nodedb:toMakeCode')")
    @ApiOperation("一键打码")
    @GetMapping(value = "/toMakeCode")
    @ResponseBody
    public ResponseData toMakeCode(String dist, Integer flag) {
        generateCode();
        try {
            generateCodeTxt(dist, flag);
            WriteMap.write();
            WareHouseDBServiceImpl wareHouseDBService = SpringContextHolder.getBean(WareHouseDBServiceImpl.class);
            List<Node> nodeList = nodeDBService.getNodeList();
            String wareHouseName = wareHouseDBService.getCurWareHouseDB().getWarehouseName();
            Integer agvMapRotate = wareHouseDBService.getCurWareHouseDB().getAgvMapRotate();
            RgvInterface.generalMap(wareHouseName, nodeList, ModuleType.RGV_60,
                    RgvMapTagDirection.parseDirection(agvMapRotate));

           /* RgvInterface.generalMap(nodeList, wareHouseName, ModuleType.RGV_ROLLER);
            RgvInterface.generalMap(nodeList, wareHouseName, ModuleType.RGV_SON_MOTHER);*/
            nodeDBService.updateNodeDBRgv60Map(nodeList);
        } catch (FileNotFoundException e) {
            return ResponseData.error("地图写入失败，请先导入位移" + e.getMessage());
        } catch (IOException e) {
            return ResponseData.error("地图写入失败！" + e.getMessage());
        }
        return ResponseData.success("生成成功！");
    }

    /**
     * 显示
     *
     * @return
     */
    @Log(title = "库区节点前端控制", method = "跑码结果显示", businessType = BusinessType.UPDATE)
    @PreAuthorize("@ss.hasPermi('nodedb:toCheckCode')")
    @ApiOperation("跑码结果显示")
    @GetMapping(value = "/toCheckCode")
    @ResponseBody
    public ResponseData toCheckCode(String dist) {
        if (nodeDBService.getCodeFlage() == 1) {
            nodeDBService.setCodeFlage(0);
            return ResponseData.success("关闭跑码结果！");
        } else {
            nodeDBService.setCodeFlage(1);
            return ResponseData.success("显示跑码结果！");
        }
    }

    /**
     * 批量下发空载
     *
     * @return
     */
    @PreAuthorize("@ss.hasPermi('nodedb:createBatchTask')")
    @PostMapping(value = "/createBatchTask")
    @ResponseBody
    public ResponseData createBatchTask(@RequestBody BatchTaskRequest batchTaskRequest) {
        List<Coord> coords = batchTaskRequest.getCoords();
        if (coords == null) {
            return ResponseData.error("请先选择目的点,按住CTRL键可以多选！");
        }
        List<TaskDB> taskDBS = new ArrayList<>();
        for (Coord coord : coords) {
            TaskDB taskDB = new TaskDB();
            Node node = new Node(coord);
            NodeDB nodedb = nodeDBService.getNodeDB(node);
            if (nodedb == null) {
                LoggerUtil.error("无法找到该坐标：" + node, this.getClass());
                return ResponseData.error("无法找到该坐标：" + node);
            }
            if (nodedb.getGridType() == NodeType.ST || nodedb.getGridType() == NodeType.B) {
                LoggerUtil.error("该坐标：" + node + "为禁用或者工位", this.getClass());
                return ResponseData.error("该坐标：" + node + "为禁用或者工位");
            }
            taskDB.setTaskType(TaskType.MOVE_UNLOADED);
            taskDB.setProcessingRgvNo(batchTaskRequest.getRgvNo());
            taskDB.setPriorityCode(CommonUtil.PRIORITY_CODE_MANUAL);
            taskDB.setEndNode(node);
            taskDBS.add(taskDB);
        }
        for (TaskDB task : taskDBS) {
            taskDBService.insertTask(Collections.singletonList(task));
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return ResponseData.success("生成成功！");
    }

    /**
     * 乱序跑码任务
     *
     * @return
     */
    @PreAuthorize("@ss.hasPermi('nodedb:createCodeTask')")
    @PostMapping(value = "/createCodeTask")
    @ResponseBody
    public ResponseData createCodeTask(@RequestBody BatchTaskRequest batchTaskRequest) {
        return runForGCode(batchTaskRequest);
    }

    /**
     * 跑码任务
     *
     * @param taskGenerate
     * @return
     */
    private ResponseData runForGCode(BatchTaskRequest taskGenerate) {
        try {
            List<Node> pathNodes = new ArrayList<>();
            for (Coord coord : taskGenerate.getCoords()) {
                pathNodes.add(new Node(coord));
            }

            LadderNavigate.generalNavigateTask(taskGenerate.getRgvNo(), pathNodes, taskDBService,
                    nodeDBService.getNodeByLayer(Collections.singletonList(pathNodes.get(0).getZ())));

            return ResponseData.success("生成跑码任务成功");
        } catch (Exception e) {
            WcsFuncUtil.exceptionLog(e, this.getClass());
            return ResponseData.error("生成跑码任务失败:" + e.getMessage());
        }
    }

    /**
     * 整层空载任务下发
     *
     * @return
     */
    @PreAuthorize("@ss.hasPermi('nodedb:createTierTask')")
    @PostMapping(value = "/createTierTask")
    @ResponseBody
    public ResponseData createTierTask(@RequestBody TierTaskRequest tierTaskRequest) {

        Rgv rgv = SystemInit.getByRgvNo(tierTaskRequest.getRgvNo());
        int nodeZ = rgv.getRgvDB().getLocationNode().getZ();
        List<NodeDB> unLoadNodeList = nodeDBService.findCargoNodes(nodeZ);
        List<TaskDB> taskDBs = new ArrayList<>();
        new Thread(() -> {
            for (NodeDB nodeDB : unLoadNodeList) {
                TaskDB taskDB = new TaskDB();
                Node node = new Node(nodeDB.getGridx(), nodeDB.getGridy(), nodeDB.getGridz());
                taskDB.setTaskType(TaskType.MOVE_UNLOADED);
                taskDB.setProcessingRgvNo(tierTaskRequest.getRgvNo());
                taskDB.setPriorityCode(CommonUtil.PRIORITY_CODE_MANUAL);
                taskDB.setEndNode(node);
                taskDBs.add(taskDB);
            }
            taskDBService.insertTask(taskDBs);
        }).start();

        return ResponseData.success("生成成功！");
    }

    /**
     * 填充地码字段
     */
    private void generateCode() {
        List<NodeDB> list = nodeDBService.list();
        StringBuilder sb = new StringBuilder();
        if (list != null) {
            list.forEach(nodeDB -> {
                sb.append(String.format("%0" + 2 + "d", nodeDB.getGridx()));
                sb.append(String.format("%0" + 2 + "d", nodeDB.getGridy()));
                sb.append(String.format("%0" + 2 + "d", nodeDB.getGridz()));
                nodeDB.setGroundCode(sb.toString());
                sb.setLength(0);
            });
            nodeDBService.updateBatchById(list);
        }
    }

    /**
     * 写货位编码到txt文件
     *
     * @param dist 库区名称
     * @param flag 1. 通道不需要生成 2. 通道生成 3. 通道生成双份
     * @throws IOException
     */
    public void generateCodeTxt(String dist, Integer flag) throws IOException {
        String paperFile = System.getProperty("user.dir") + File.separator + "wcs_map" + File.separator + dist + File.separator + dist;
        //创建文件夹
        String filename = paperFile + "code.txt";
        WriteMap.createPaper(filename);
        File file = new File(filename);
        BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(file));
        //判断是按照x方向，还是y方向写入txt
        List<NodeDB> list = nodeDBService.getNodeDbNeedPrintCodeByX();
        for (NodeDB nodeDB : list) {
            if (nodeDB.getCanToDown() || nodeDB.getCanToUp()) {
                break;
            } else if (nodeDB.getCanToLeft() || nodeDB.getCanToRight()) {
                list = nodeDBService.getNodeDbNeedPrintCodeByY();
                break;
            }
        }
        for (NodeDB node : list) {
            if (node.getGroundCode() != null
                    && !NodeType.CONNECTION.equals(node.getGridType())
                    && !NodeType.L.equals(node.getGridType())
                    && !NodeType.B.equals(node.getGridType())) {
                if (flag == 2) {
                    if (!NodeType.R.equals(node.getGridType())) {
                        bufferedWriter.write(node.getGroundCode() + "490");
                        bufferedWriter.write("   ");
                        bufferedWriter.write(node.getGroundCode() + "500");
                        bufferedWriter.write("   ");
                        bufferedWriter.write(node.getGroundCode() + "510");
                        bufferedWriter.newLine();
                    }
                } else {
                    bufferedWriter.write(node.getGroundCode() + "490");
                    bufferedWriter.write("   ");
                    bufferedWriter.write(node.getGroundCode() + "500");
                    bufferedWriter.write("   ");
                    bufferedWriter.write(node.getGroundCode() + "510");
                    bufferedWriter.newLine();
                    if (flag == 3 && NodeType.R.equals(node.getGridType())) {
                        bufferedWriter.write(node.getGroundCode() + "490");
                        bufferedWriter.write("   ");
                        bufferedWriter.write(node.getGroundCode() + "500");
                        bufferedWriter.write("   ");
                        bufferedWriter.write(node.getGroundCode() + "510");
                        bufferedWriter.newLine();
                    }
                }
            }
        }
        bufferedWriter.close();
    }


    /**
     * 获取指定参数列表(从数据库)
     *
     * @param floor 层
     * @param dist  库区
     * @return
     */
    @GetMapping(value = "/getNodeList")
    @ResponseBody
    @ApiOperation(value = "根据传入的层和库区获取节点数据")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "floor", value = "仓库层数"),
            @ApiImplicitParam(name = "dist", value = "库区ID")
    })
    public ResponseData getNodeList(@RequestParam(defaultValue = "1", required = false) Integer floor,
                                    @RequestParam(required = false) String dist) {
        List<NodeDB> result = nodeDBService.getNodeDBByFloor(floor);
        int maxX = nodeDBService.getMaxX();
        int maxY = nodeDBService.getMaxY();
        NodeDB[][] nodeDBS = new NodeDB[maxX][maxY];
        // 给二维数组赋值
        for (NodeDB nodeDB : result) {
            analyzeData(nodeDB);
            nodeDBS[(nodeDB.getGridx() - 1)][(nodeDB.getGridy() - 1)] = nodeDB;
        }
        Map<String, NodeDB[][]> map = new HashMap<>();
        map.put("nodedb", nodeDBS);
        return ResponseData.success("查询成功", map);
    }

    private static void analyzeData(NodeDB nodeDB) {
        nodeDB.setRunForGCodeStatus(NodeInfoPush.analyzeRunForGCode(nodeDB.getRunUpForGroundCodeStatus(),
                nodeDB.getRunDownForGroundCodeStatus(), nodeDB.getRunLeftForGroundCodeStatus(),
                nodeDB.getRunRightForGroundCodeStatus(), nodeDB.getCanToUp(), nodeDB.getCanToDown(),
                nodeDB.getCanToLeft(), nodeDB.getCanToRight()));
        nodeDB.setCalibrationTimeStatus(NodeInfoPush.analyzeCalibrationTime(nodeDB.getUpCalibrationTime(),
                nodeDB.getDownCalibrationTime(), nodeDB.getLeftCalibrationTime(),
                nodeDB.getRightCalibrationTime(), nodeDB.getCanToUp(), nodeDB.getCanToDown(),
                nodeDB.getCanToLeft(), nodeDB.getCanToRight()));
    }

    /**
     * 获取库区对应XYZ
     */
    @ApiOperation("获取库区对应XYZ")
    @GetMapping(value = "/getRegion")
    @ResponseBody
    public ResponseData getRegion(@RequestParam String dist) {
        List<NodeDB> xNodeDBS = nodeDBService.getRegion("gridx");
        List<NodeDB> yNodeDBS = nodeDBService.getRegion("gridy");
        List<NodeDB> zNodeDBS = nodeDBService.getRegion("gridz");
        List<Integer> xRegion = new ArrayList<>();
        List<Integer> yRegion = new ArrayList<>();
        List<Integer> zRegion = new ArrayList<>();
        Map<String, List> map = new HashedMap<>();
        if (xNodeDBS != null && xNodeDBS.size() > 0) {
            xNodeDBS.forEach(xNode -> {
                xRegion.add(xNode.getGridx());
            });
        }
        if (yNodeDBS != null && yNodeDBS.size() > 0) {
            yNodeDBS.forEach(yNode -> {
                yRegion.add(yNode.getGridy());
            });
        }
        if (zNodeDBS != null && zNodeDBS.size() > 0) {
            zNodeDBS.forEach(zNode -> {
                zRegion.add(zNode.getGridz());
            });
        }
        map.put("x", xRegion);
        map.put("y", yRegion);
        map.put("z", zRegion);
        return ResponseData.success(map);
    }

    /**
     * 获取库区对应XYZ
     */
    @ApiOperation("获取库区对应XYZ")
    @GetMapping(value = "/getRegionNoDist")
    @ResponseBody
    public ResponseData getRegion() {
        List<NodeDB> xNodeDBS = nodeDBService.getRegion("gridx");
        List<NodeDB> yNodeDBS = nodeDBService.getRegion("gridy");
        List<NodeDB> zNodeDBS = nodeDBService.getRegion("gridz");
        List<Integer> xRegion = new ArrayList<>();
        List<Integer> yRegion = new ArrayList<>();
        List<Integer> zRegion = new ArrayList<>();
        Map<String, List> map = new HashedMap<>();
        if (xNodeDBS != null && xNodeDBS.size() > 0) {
            xNodeDBS.forEach(xNode -> {
                xRegion.add(xNode.getGridx());
            });
        }
        if (yNodeDBS != null && yNodeDBS.size() > 0) {
            yNodeDBS.forEach(yNode -> {
                yRegion.add(yNode.getGridy());
            });
        }
        if (zNodeDBS != null && zNodeDBS.size() > 0) {
            zNodeDBS.forEach(zNode -> {
                zRegion.add(zNode.getGridz());
            });
        }
        map.put("x", xRegion);
        map.put("y", yRegion);
        map.put("z", zRegion);
        return ResponseData.success(map);
    }

    /**
     * 修改节点对象数据
     *
     * @param nodedb
     * @return
     * @throws IOException
     */
    @Log(title = "库区节点前端控制", method = "修改节点对象数据", businessType = BusinessType.UPDATE)
    @PreAuthorize("@ss.hasPermi('nodedb:editNode')")
    @PostMapping(value = "/editNode")
    @ResponseBody
    @ApiOperation(value = "修改节点对象数据")
    public ResponseData editNode(@RequestBody NodeDB nodedb) throws IOException {
        ResponseData result = checkIsCanChange(nodedb);
        if (result != null) return result;

        if (NodeType.AD.equals(nodedb.getGridType())) {
            nodedb.setCanToStop(false);
            nodedb.setIsDoor(true);
        } else {
            nodedb.setIsDoor(false);
        }
        if (nodedb.getNodeRgvType() != null) {
            StringBuffer forbidRgvsStr = new StringBuffer();
            for (int i = 0; i < nodedb.getNodeRgvType().length; i++) {
                Long plcDeviceId = nodedb.getNodeRgvType()[i];
                forbidRgvsStr.append(plcDeviceId + "-");
            }

            if (StringUtils.isNotEmpty(forbidRgvsStr)) {
                nodedb.setForbidRgvs(forbidRgvsStr.delete(forbidRgvsStr.lastIndexOf("-"), forbidRgvsStr.length()).toString());
            } else {
                nodedb.setForbidRgvs("");
            }
        }
        nodeDBService.updateNodeDBInfo(nodedb);
        NodeInfo nodeInfo = new NodeInfo();
        BeanUtils.copyProperties(nodedb, nodeInfo);
        NodeInfoPush.push(nodeInfo);
        log.info("手动更新节点信息 " + nodedb);
        WriteMapUtil.writeMap();
        log.info("手动更新节点信息完成");
        return ResponseData.success("修改成功");
    }

    /**
     * 修改节点对象数据
     *
     * @param detailId
     * @return
     * @throws IOException
     */
    @Log(title = "库区节点前端控制", method = "修改节点对象数据", businessType = BusinessType.UPDATE)
    @PreAuthorize("@ss.hasPermi('nodedb:editNode')")
    @GetMapping(value = "/editStatus")
    @ResponseBody
    @ApiOperation(value = "修改节点对象数据")
    public ResponseData editStatus(Integer detailId) throws IOException {
        if (null == detailId) {
            return ResponseData.error("参数不能为空");
        }
        TaskDetailDB detailDB = taskDetailService.getById(detailId);
        NodeDB nodeDB = nodeDBService.getNodeDB(Node.parseGrid(detailDB.getDeviceInfo()));
        if (DetailProcess.HOIST_UPDATE_Y.getDescription().equals(detailDB.getProcess())) {
            nodeDBService.updateLifterLeftOrRightNodeDB(Node.parseGrid(detailDB.getDeviceInfo()), NodeStatus.Y.toString());
        } else if (DetailProcess.HOIST_UPDATE_N.getDescription().equals(detailDB.getProcess())) {
            nodeDBService.updateLifterLeftOrRightNodeDB(Node.parseGrid(detailDB.getDeviceInfo()), NodeStatus.N.toString());
        }
        taskDetailService.updateTaskDetailCompleteTime(detailDB);
        NodeInfo nodeInfo = new NodeInfo();
        BeanUtils.copyProperties(nodeDB, nodeInfo);
        NodeInfoPush.push(nodeInfo);
        log.info("手动更新节点信息 " + nodeDB);
        WriteMapUtil.writeMap();
        return ResponseData.success("修改成功");
    }

    /**
     * 修改节点对象数据
     *
     * @param nodedb
     * @return
     * @throws IOException
     */
    @Log(title = "库区节点前端控制", method = "修改节点对象数据", businessType = BusinessType.UPDATE)
    @PreAuthorize("@ss.hasPermi('nodedb:editNode')")
    @PostMapping(value = "/edit")
    @ResponseBody
    @ApiOperation(value = "修改节点对象数据")
    public ResponseData edit(@RequestBody NodeDB nodedb) throws IOException {
        ResponseData result = checkIsCanChange(nodedb);
        if (result != null) return result;

        if (NodeType.AD.equals(nodedb.getGridType())) {
            nodedb.setIsDoor(true);
        } else {
            nodedb.setIsDoor(false);
        }

        nodeDBService.changeFBGIntToString(nodedb);

        nodeDBService.updateById(nodedb);
        NodeInfo nodeInfo = new NodeInfo();
        BeanUtils.copyProperties(nodedb, nodeInfo);
        NodeInfoPush.push(nodeInfo);
        log.info("手动更新节点信息 " + nodedb);
        WriteMapUtil.writeMap();
        return ResponseData.success("修改成功");
    }

    /**
     * 是否可以更改节点信息
     *
     * @param nodedb
     * @return
     */
    private ResponseData checkIsCanChange(@RequestBody NodeDB nodedb) {
        if (null == nodedb || nodedb.getNodeId() == null) {
            return ResponseData.error("参数不能为空");
        }
        if (!StringUtils.isEmpty(nodedb.getGroundCode())) {
            List<NodeDB> list = nodeDBService.getNodeDBsByGroundCode(nodedb.getGroundCode());
            for (NodeDB nodeDB : list) {
                if (!nodedb.getGridType().equals(NodeType.L) && !nodeDB.getGridType().equals(NodeType.L)) {
                    if (!nodeDB.getGridx().equals(nodedb.getGridx()) || !nodeDB.getGridy().equals(nodedb.getGridy())
                            || !nodeDB.getGridz().equals(nodedb.getGridz())) {
                        return ResponseData.error("数据库中已存在此地码！");
                    }
                }
            }
        }
        if (nodedb.getCanToLeft() && !nodedb.getCanToStop()) {
            NodeDB nodeDB1 = nodeDBService.getNodeDB(new Coord(nodedb.getGridx(), nodedb.getGridy() - 1, nodedb.getGridz()));
            if (NodeType.L.equals(nodeDB1.getGridType())) {
                return ResponseData.error("提升机周围不可设置不可停！");
            }
        }
        if (nodedb.getCanToRight() && !nodedb.getCanToStop()) {
            NodeDB nodeDB1 = nodeDBService.getNodeDB(new Coord(nodedb.getGridx(), nodedb.getGridy() + 1, nodedb.getGridz()));
            if (NodeType.L.equals(nodeDB1.getGridType())) {
                return ResponseData.error("提升机周围不可设置不可停！");
            }
        }
        if (nodedb.getCanToUp() && !nodedb.getCanToStop()) {
            NodeDB nodeDB1 = nodeDBService.getNodeDB(new Coord(nodedb.getGridx() - 1, nodedb.getGridy(), nodedb.getGridz()));
            if (NodeType.L.equals(nodeDB1.getGridType())) {
                return ResponseData.error("提升机周围不可设置不可停！");
            }
        }
        if (nodedb.getCanToDown() && !nodedb.getCanToStop()) {
            NodeDB nodeDB1 = nodeDBService.getNodeDB(new Coord(nodedb.getGridx() + 1, nodedb.getGridy(), nodedb.getGridz()));
            if (NodeType.L.equals(nodeDB1.getGridType())) {
                return ResponseData.error("提升机周围不可设置不可停！");
            }
        }
        return null;
    }

    /**
     * 切换节点是否有货
     *
     * @param nodeId, gridStatus
     * @return ResponseData
     */
    @Log(title = "库区节点前端控制", method = "切换节点是否有货", businessType = BusinessType.UPDATE)
    @GetMapping(value = "/editGridStatus")
    @ResponseBody
    @ApiOperation(value = "切换节点是否有货")
    public ResponseData editNode(String nodeId) {
        NodeDB nodedb;
        if (nodeId == null) {
            return ResponseData.error("请选择货位");
        }
        try {
            nodedb = nodeDBService.getById(nodeId);
        } catch (Exception e) {
            return ResponseData.error("编号为 " + nodeId + " 的货位信息不存在");
        }
        if (NodeType.R.equals(nodedb.getGridType()) && NodeStatus.N.toString().equals(nodedb.getGridStatus())) {
            return ResponseData.error("通道不可设置为有货");
        }
        if ((NodeType.L.equals(nodedb.getGridType()) || NodeType.TL.equals(nodedb.getGridType())) && NodeStatus.N.toString().equals(nodedb.getGridStatus())) {
            return ResponseData.error("提升机不可设置为有货");
        }
        if (NodeType.ST.equals(nodedb.getGridType()) && NodeStatus.N.toString().equals(nodedb.getGridStatus())) {
            return ResponseData.error("工位不可设置为有货");
        }
        log.info("接收到切换编号为 " + nodeId + " 的货位是否有货的指令");
        if (NodeStatus.N.toString().equals(nodedb.getGridStatus())) {
            nodedb.setGridStatus(NodeStatus.Y.toString());
        } else if (NodeStatus.Y.toString().equals(nodedb.getGridStatus())) {
            nodedb.setGridStatus(NodeStatus.N.toString());
        }
        nodeDBService.updateById(nodedb);
        NodeInfo nodeInfo = new NodeInfo();
        BeanUtils.copyProperties(nodedb, nodeInfo);
        NodeInfoPush.push(nodeInfo);
        return ResponseData.success("修改成功");
    }


    /**
     * 获取所有任务类型
     */
    @PostMapping(value = "/getAllTaskType")
    @ResponseBody
    @ApiOperation(value = "获取所有任务类型")
    public ResponseData getAllTaskType() {
        List<TaskType> taskManagerType = (Arrays.asList(TaskType.values()));
        List<BaseEum> taskTypeList = new ArrayList<BaseEum>();
        for (TaskType taskType : taskManagerType) {
            taskTypeList.add(new BaseEum(taskType.getTypeNum(), taskType.toString()));
        }
        return ResponseData.success(taskTypeList);
    }

    /**
     * 上传数据,插入数据库
     *
     * @param file 文件
     * @return code:0(成功),-1(失败,出现错误),-2(未登录状态) data:数据 message:传递到页面的数据
     */
    @Log(title = "库区节点前端控制", method = "上传数据,插入数据库", businessType = BusinessType.UPDATE)
    @PreAuthorize("@ss.hasPermi('nodedb:importData')")
    @ApiOperation("上传数据,插入数据库")
    @PostMapping("/importData")
    @ResponseBody
    public ResponseData importData(MultipartFile file, boolean updateSupport) throws IOException {
        String message = readExcel.readData(file.getInputStream(), updateSupport);
        return ResponseData.success(message);
    }

    /**
     * 上传数据,插入数据库
     *
     * @param file 文件
     * @return code:0(成功),-1(失败,出现错误),-2(未登录状态) data:数据 message:传递到页面的数据
     */
    @Log(title = "库区节点前端控制", method = "导入位移数据", businessType = BusinessType.UPDATE)
    @PreAuthorize("@ss.hasPermi('nodedb:importData')")
    @ApiOperation("导入位移数据")
    @PostMapping("/importOffsetData")
    @ResponseBody
    public ResponseData importOffsetData(MultipartFile file, Integer layer) {
        try {
            List<Node> nodeList = nodeDBService.getNodeList();
            WareHouseDB curWareHouseDB = wareHouseDBService.getCurWareHouseDB();
            RgvInstance.loadRgvSmap(layer, file.getInputStream(), nodeList
                    , curWareHouseDB.getWarehouseName(), ModuleType.RGV_60,
                    RgvMapTagDirection.parseDirection(curWareHouseDB.getAgvMapRotate()));
            nodeDBService.updateNodeDBRgv60Map(nodeList);
            return ResponseData.success("位移加载成功");
        } catch (Exception e) {
            WcsFuncUtil.exceptionLog(e, this.getClass());
            return ResponseData.error("位移导入失败");
        }
    }

    /**
     * 获取某层被锁节点
     *
     * @param floor
     * @return
     */
    @GetMapping("lockNodes")
    @ApiOperation(value = "获取某层被锁节点")
    public ResponseData getLockNodes(@RequestParam(defaultValue = "1", required = false) Integer floor) {
        if (null == floor || floor < 1) {
            return ResponseData.error("参数有误");
        }
        Map<String, List<ResourcesLockNodeBO>> map = new HashMap<>();
        map.put("nodeBOs", nodeDBService.getLockNodes(floor));
        return ResponseData.success("查询成功", 1);
    }

    /**
     * 获取某层资源节点
     *
     * @param floor
     * @return
     */
    @GetMapping("getResourcesNodes")
    @ApiOperation(value = "获取某层资源节点")
    public ResponseData getResourcesNodes(@RequestParam(defaultValue = "1", required = false) Integer floor) {
        if (null == floor || floor < 1) {
            return ResponseData.error("参数有误");
        }
        Map<String, List<ResourcesNodeBO>> map = new HashMap<>();
        map.put("nodeBOs", nodeDBService.getResourcesNodes(floor));
        return ResponseData.success("查询成功", 1);
    }

    /**
     * 强行解锁某个节点
     *
     * @param coord
     * @return
     */
    @Log(title = "库区节点前端控制", method = "强行解锁某个节点", businessType = BusinessType.UPDATE)
    @PutMapping("/unLockNode")
    @ApiOperation(value = "强行解锁某个节点")
    public ResponseData unLockNode(@RequestBody Coord coord) {
        if (coord == null) {
            return ResponseData.error("参数有误");
        }
        nodeDBService.unLockNode(coord);
        return ResponseData.success("解锁成功", 1);
    }

    /**
     * 加锁某个节点
     *
     * @param coord
     * @return
     */
    @Log(title = "库区节点前端控制", method = "加锁某个节点", businessType = BusinessType.UPDATE)
    @PutMapping("/lockNode")
    @ApiOperation(value = "加锁某个节点")
    public ResponseData lockNode(@RequestBody Coord coord) {
        if (coord == null) {
            return ResponseData.error("参数有误");
        }
        HashSet<Coord> coords = new HashSet<Coord>();
        coords.add(coord);
        LockNodeManager.lockedNodes(coords, UUID.randomUUID().toString());
//        nodeDBService.unLockNode(coord);
        return ResponseData.success("加锁成功", 1);
    }


    /**
     * 巷道划分
     */
    @PreAuthorize("@ss.hasPermi('nodedb:rodeDivide')")
    @PutMapping(value = "/rodeDivide/{divides}")
    @ApiOperation(value = "获取所有任务类型")
    public ResponseData rodeDivide(@PathVariable List<Integer> divides) {
        List<NodeDB> list = nodeDBService.list();
        List<NodeDB> nodeDBS = readExcel.rodeDivide(list, divides);
        boolean result = nodeDBService.updateBatchById(nodeDBS, nodeDBS.size());
        return toAjax(result);
    }


    /**
     * 地码文件下载请求
     *
     * @param dist   库区名
     * @param delete 是否删除
     */
    @ApiOperation(value = "地码文件下载")
    @GetMapping("/download")
    public void fileDownload(String dist, Boolean delete, HttpServletResponse response, HttpServletRequest request) {
        try {

            String filePath = System.getProperty("user.dir") + File.separator + "wcs_map" + File.separator + dist + File.separator + dist + "code.txt";

            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
            FileUtils.setAttachmentResponseHeader(response, dist + "code.txt");
            FileUtils.writeBytes(filePath, response.getOutputStream());
            if (delete) {
                FileUtils.deleteFile(filePath);
            }
        } catch (Exception e) {
            log.error("下载文件失败", e);
        }
    }

    @PreAuthorize("@ss.hasPermi('node:setForbidRgvTypes')")
    @Log(title = "节点管理", method = "添加禁行车辆类型", businessType = BusinessType.UPDATE)
    @GetMapping("/setForbidRgvTypes")
    @ResponseBody
    @ApiOperation("添加禁行车辆类型")
    public ResponseData setForbidRgvTypes(@RequestParam String node, @RequestParam Integer nodeRgvType) {
        try {
            if (nodeDBService.addForbidRgv(Node.parseGrid(node), nodeRgvType)) {
                return ResponseData.success("添加成功", null);
            } else {
                return ResponseData.success("添加失败", null);
            }
        } catch (Exception e) {
            WcsFuncUtil.exceptionLog(e, this.getClass());
            return ResponseData.success("添加失败", null);
        }
    }

    @PreAuthorize("@ss.hasPermi('node:setAllowedRgvTypes')")
    @Log(title = "节点管理", method = "删除禁行车辆类型", businessType = BusinessType.UPDATE)
    @GetMapping("/setAllowedRgvTypes")
    @ResponseBody
    @ApiOperation("删除禁行车辆类型")
    public ResponseData setAllowedRgvTypes(@RequestParam String node, @RequestParam Integer nodeRgvType) {
        try {
            if (nodeDBService.removeForbidRgv(Node.parseGrid(node), nodeRgvType)) {
                return ResponseData.success("删除成功", null);
            } else {
                return ResponseData.success("删除失败", null);
            }
        } catch (Exception e) {
            WcsFuncUtil.exceptionLog(e, this.getClass());
            return ResponseData.success("删除失败", null);
        }
    }

    /**
     * 跑码清空
     *
     * @param coord
     * @return
     */
    @Log(title = "库区节点前端控制", method = "跑码清空", businessType = BusinessType.UPDATE)
    @PutMapping("/nodeCodeClean")
    @ApiOperation(value = "跑码清空")
    public ResponseData nodeCodeClean(@RequestBody Coord coord) {
        if (coord == null) {
            return ResponseData.error("参数有误");
        }
        NodeDB nodeDB = nodeDBService.getNodeDB(coord);
        if (nodeDB != null) {
            nodeDB.setRunUpForGroundCodeStatus(0);
            nodeDB.setRunDownForGroundCodeStatus(0);
            nodeDB.setRunLeftForGroundCodeStatus(0);
            nodeDB.setRunRightForGroundCodeStatus(0);
            nodeDB.setUpCalibrationTime(0);
            nodeDB.setDownCalibrationTime(0);
            nodeDB.setLeftCalibrationTime(0);
            nodeDB.setRightCalibrationTime(0);
            nodeDBService.updateNodeDBInfo(nodeDB);
        } else {
            return ResponseData.error("参数有误");
        }
        return ResponseData.success("跑码清空", 1);
    }
}
